/* ---------------------------------------------------------------------
 *
 * -- Privacy-preserving Sharing of Sensitive information Toolkit (PSST)
 *    (C) Copyright 2010 All Rights Reserved
 *
 * -- PSST routines -- Version 1.0.1 -- April, 2010
 * Bcckls corresponds to protocol JL09 in the paper
 *
 * Author         : Yanbin Lu
 * Security and Privacy Research Outfit (SPROUT),
 * University of California, Irvine
 *
 * -- Bug report: send email to yanbinl@uci.edu
 * ---------------------------------------------------------------------
 *
 * -- Copyright notice and Licensing terms:
 *
 *  Redistribution  and  use in  source and binary forms, with or without
 *  modification, are  permitted provided  that the following  conditions
 *  are met:
 *
 * 1. Redistributions  of  source  code  must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce  the above copyright
 *    notice,  this list of conditions, and the  following disclaimer in
 *    the documentation and/or other materials provided with the distri-
 *    bution.
 * 3. The name of the University,  the SPROUT group,  or the names of its
 *    authors  may not be used to endorse or promote products deri-
 *    ved from this software without specific written permission.
 *
 * -- Disclaimer:
 *
 * THIS  SOFTWARE  IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,  INCLUDING,  BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY
 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,  INDIRECT, INCIDENTAL, SPE-
 * CIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
 * TO,  PROCUREMENT  OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
 * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEO-
 * RY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT  (IN-
 * CLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 */

#include "bcckls_psi_client.h"
#include "crypto_tool.h"
#include "basic_tool.h"
#include "mpz_tool.h"

Bcckls_Client::Bcckls_Client()
{
  m_qq = Memreuse::New();
  m_pp = Memreuse::New();
  m_gg = Memreuse::New();
  m_e = Memreuse::New();
  m_g = Memreuse::New();
  m_h = Memreuse::New();
  m_n = Memreuse::New();
  m_n2 = Memreuse::New();
  m_q = Memreuse::New();
  m_sk = Memreuse::New();
  m_pk = Memreuse::New();
  m_r1 = Memreuse::New();
  m_r2 = Memreuse::New();
  m_Cku = Memreuse::New();
  m_Cke = Memreuse::New();
  m_Cr2u = Memreuse::New();
  m_Cr2e = Memreuse::New();
}

void Bcckls_Client::LoadData()
{
  m_set.clear();
  m_rawset.clear();

  ifstream infile(m_strInputFile.c_str());
  if (!infile)
	{
	  cerr<<"open "<<m_strInputFile<<" error"<<endl;
	  return;
	}
  string element;
  while (getline(infile, element) && infile.good())
	{
	  m_rawset.push_back(element);
	  mpz_t * e = Memreuse::New();
	  string hs = CryptoTool::Hash(element);
	  MpzTool::Mpz_from_string(e, hs);
	  mpz_mod(*e, *e, *m_qq);
	  m_set.push_back(e);
	}
}

void Bcckls_Client::Setup(int nbits)
{

  stringstream keyfile;
  keyfile<<"rsa."<<nbits<<".pub";
  BasicTool::Load_RSA_Pub_Key(keyfile.str(), m_e, m_n, m_g, m_q);
  mpz_add_ui(*m_h, *m_n, 1);
  mpz_mul(*m_n2, *m_n, *m_n);

  mpz_t * mpz_2n = Memreuse::New();
  rn.Get_Z_Range(m_g, m_n2);
  mpz_mul_ui(*mpz_2n, *m_n, 2);
  mpz_powm(*m_g, *m_g, *mpz_2n, *m_n2);
  Memreuse::Delete(mpz_2n);

  rn.Get_Z_Range(m_sk, m_q);
  mpz_powm(*m_pk, *m_g, *m_sk, *m_n2);

  BasicTool::Load_DSA_Pub_Key(m_pp, m_qq, m_gg, NULL, "dsa.1024.pub"); // m_qq 160bits

  LoadData();
  rn.Initialize(nbits);
}

void Bcckls_Client::Initialize(int nbits)
{
  rn.Get_Z_Range(m_r1, m_qq);
  rn.Get_Z_Range(m_r2, m_qq);
  mpz_mul(*m_r2, *m_r2, *m_qq);
}

void Bcckls_Client::StoreData(const vector<string>& input)
{
  MpzTool::Mpz_from_string(m_pk, input[0]);
  MpzTool::Mpz_from_string(m_Cku, input[1]);
  MpzTool::Mpz_from_string(m_Cke, input[2]);

  for (size_t i = 3; i < input.size(); i++)
	{
	  m_data.push_back(input[i]);
	}
  CryptoTool::CSEnc(m_Cr2u, m_Cr2e, m_r2, m_g, m_h, m_pk, m_q, m_n, m_n2);
}

int Bcckls_Client::Request1(vector<string>& output)
{
  mpz_t * e2u = Memreuse::New();
  mpz_t * e2e = Memreuse::New();
  mpz_t * Cmu = Memreuse::New();
  mpz_t * Cme = Memreuse::New();

  for (size_t i = 0; i < m_set.size(); i++)
    {
	  CryptoTool::CSEnc(Cmu, Cme, m_set[i], m_g, m_h, m_pk, m_q, m_n, m_n2);
	  mpz_mul(*e2u, *m_Cku, *Cmu);
	  mpz_mod(*e2u, *e2u, *m_n2);
	  mpz_mul(*e2e, *m_Cke, *Cme);
	  mpz_mod(*e2e, *e2e, *m_n2);

	  mpz_powm(*e2u, *e2u, *m_r1, *m_n2);
	  mpz_powm(*e2e, *e2e, *m_r1, *m_n2);

	  mpz_mul(*e2u, *e2u, *m_Cr2u);
	  mpz_mod(*e2u, *e2u, *m_n2);
	  mpz_mul(*e2e, *e2e, *m_Cr2e);
	  mpz_mod(*e2e, *e2e, *m_n2);
	  output.push_back(MpzTool::Mpz_to_string(e2u));
	  output.push_back(MpzTool::Mpz_to_string(e2e));
	}
  Memreuse::Delete(e2u);
  Memreuse::Delete(e2e);
  Memreuse::Delete(Cmu);
  Memreuse::Delete(Cme);
  return 0;
}

int Bcckls_Client::OnResponse1(const vector<string>& input)
{
  mpz_t * sigma = Memreuse::New();
  for (size_t i = 0; i < input.size(); i++)
	{
	  MpzTool::Mpz_from_string(sigma, input[i]);
	  mpz_powm(*sigma, *sigma, *m_r1, *m_pp);
	  m_mapTp[CryptoTool::Hash(sigma)] = i;
	}
  map<string, size_t>::iterator it;
  for (size_t i = 0; i < m_data.size(); i++)
	{
	  if ((it = m_mapTp.find(m_data[i])) != m_mapTp.end())
		{
		  m_vecResult.push_back(it->second);
		}
	}
  return 0;
}
